#ifndef BUFFERS_H
#define BUFFERS_H

#include "postgres.h"
#include "postgres_ext.h"
#include "storage/block.h"
#include "port/atomics.h"
#include "storage/lwlock.h"
#include "utils/wait_event.h"
#include "storage/fd.h"
#include "utils/elog.h"
#include "storage/shmem.h"
#include "utils/hsearch.h"
#include "storage/relfilenode.h"

typedef struct ExtentLocation {
    int fd;
    RelFileNode relFileNode;
    BlockNumber extentNumber;
    BlockNumber extentStart;
    BlockNumber extentOffset;
    BlockNumber headerNum;
    uint16 chrunkSize;
    uint8 algorithm;
}KPHCExtentLocation;

typedef struct CfsBufferKey {
    RelFileNode relFileNode;
    uint32 extentCount;
}KPHCCfsBufferKey;

typedef enum enCtrlState {
    CTRL_STATE_INIT = 0,
    CTRL_STATE_USED = 1, 
    CTRL_STATE_FREE = 2,
} KPHCCtrlState;

typedef enum enCtrlLoadStatus {
    CTRL_PAGE_NO_LOAD,
    CTRL_PAGE_IS_LOADED,
    CTRL_PAGE_LOADED_ERROR
} KPHCCtrlLoadStatus;

typedef struct CfsExtentAddress {
    uint32 checksum;
    volatile uint8 nchunks;
    volatile uint8 allocated_chunks;
    uint16 chunknos[FLEXIBLE_ARRAY_MEMBER];
}KPHCCfsExtentAddress;

typedef struct CfsExtentHeader {
    pg_atomic_uint32 nblocks;
    pg_atomic_uint32 allocated_chunks;
    uint16 chunk_size;
    uint8 algorithm : 7;
    uint8 recycleInOrder : 1;
    uint8 recv;
    KPHCCfsExtentAddress cfsExtentAddress[FLEXIBLE_ARRAY_MEMBER];
}KPHCCfsExtentHeader;

typedef struct __attribute__((aligned(128))) stPciPageCtrl
{
    uint32 ctrlId;        
    KPHCCtrlState state;    
    volatile uint32 lruPrev;
    volatile uint32 lruNext;
    volatile uint32 bckPrev;
    volatile uint32 bckNext;
    volatile uint32 bckId;
    pg_atomic_uint32 touchNum;
    pg_atomic_uint32 refNum;

    LWLock *contentLock; 
    KPHCCtrlLoadStatus loadStatus;

    KPHCCfsBufferKey pciKey;  
    KPHCCfsExtentHeader *pciPage; 
} KPHCPciPageCtrl;

typedef struct stPciHashBucket {
    LWLock *lock;
    uint32 bckId;

    uint32 ctrlCount;    
    uint32 firstCtrlId;
} KPHCPciHashBucket;

typedef struct stPciPageHashtbl {
    HashValueFunc hash;      
    HashCompareFunc match;  

    uint32 bucketNum;
    KPHCPciHashBucket *buckets;
} KPHCPciPageHashtbl;

typedef struct stPciLruList {
    LWLock *lock;  
    volatile uint32 count;
    volatile uint32 first;
    volatile uint32 last;
} KPHCPciLruList;

#define PCI_PART_LIST_NUM (8)
#define PCI_LRU_LIST_NUM (PCI_PART_LIST_NUM * 2)

typedef struct __attribute__((aligned(128))) stPciPageBuffCtx
{
    KPHCPciPageCtrl *ctrlBuf;     
    char *pageBuf;                
    KPHCPciPageHashtbl hashtbl;

    uint32 maxCount; 
    KPHCPciLruList mainLru[PCI_PART_LIST_NUM];
    KPHCPciLruList freeLru[PCI_PART_LIST_NUM];
} KPHCPciPageBuffCtx;

#define PCI_INVALID_ID (0)
#define PCI_GET_CTRL_BY_ID(ctx, ctrlId) ((KPHCPciPageCtrl *)(&(ctx->ctrlBuf[(ctrlId) - 1])))
#define PCI_GET_BUCKET_BY_ID(ctx, bckId) ((KPHCPciHashBucket *)(&(ctx->hashtbl.buckets[(bckId) - 1])))
#define PCI_GET_BUCKET_BY_HASH(ctx, hashcode) (PCI_GET_BUCKET_BY_ID(ctx, (((hashcode) % ctx->hashtbl.bucketNum) + 1)))

#define PCI_SET_NO_READ(ctrl) (ctrl->loadStatus = CTRL_PAGE_NO_LOAD)

typedef enum pciBufferReadMode {
    PCI_BUF_NORMAL_READ,
    PCI_BUF_NO_READ
} KPHCPciBufferReadMode;

extern KPHCPciPageBuffCtx *gPciBufCtx;

void KPHCPciBufInitCtx();

KPHCPciPageCtrl *KPHCPciBufReadPage(const KPHCExtentLocation location, LWLockMode lockMode, KPHCPciBufferReadMode readMode);

void KPHCPciBufFreePage(KPHCPciPageCtrl *ctrl, const KPHCExtentLocation location, bool need_write);
Size KPHCPciBufferSize();
uint32 KPHCPciLockCount();

#endif // BUFFERS_H
